﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CNShapes;
using BobcatMultiTouch;
using System.Drawing;
using MouseKeyboardLibrary;
using System.Windows.Forms;

namespace CNPageEditor
{
    public class Action_AddText : Action
    {
        #region Action methods

        /// <summary>
        /// Called when the action is created.
        /// </summary>
        public override void initialize()
        {
            // We create a text shape and set the font size, scaled by the zoom factor...
            m_TextShape = new Shape_Text();
			m_TextShape.setIsBeingEdited(true, getActionOrigin());
            float fFontSize = m_TextShape.getFontSize() / m_PageViewerControl.ZoomFactor;
            m_TextShape.setFontSize(fFontSize, getActionOrigin());

            // We add the shape to the page...
            m_Page.addShape(m_TextShape, getActionOrigin());

            // TODO: remove this?
            // We register for keyboard events.
            m_Keyboard.Start();
            m_Keyboard.KeyPress += onKeyPress;

            // We set the shape to be at the current cursor position 
            // (if there is one)...
            IList<TouchArgs> touches = m_PageEditorControl.MTIC.getActiveTouches();
            if (touches.Count != 1)
            {
                return;
            }

            // We get the cursor position in "shape coordinates"...
            Point screenPoint = touches[0].ClientPosition;
            PointF shapePosition = m_PageViewerControl.clientPointToShapePoint(screenPoint);
            m_TextShape.setTopLeft(shapePosition, getActionOrigin());
        }

		/// <summary>
		/// Called when the action becomes inactive.
		/// </summary>
		public override void deactivate()
		{
			m_TextShape.setIsBeingEdited(false, getActionOrigin());
			m_Keyboard.KeyPress -= onKeyPress;
			m_Keyboard.Stop();
		}

		/// <summary>
        /// returns the readable description of the action.
        /// </summary>
        public override string getDescription()
        {
            return "Add text";
        }


        /// <summary>
        /// This action supports undo.
        /// </summary>
        public override bool supportsUndo()
        {
            return true;
        }

        /// <summary>
        /// This action can be repeated after completion.
        /// </summary>
        public override bool isRepeatable()
        {
            return true;
        }

        /// <summary>
        /// Undoes the action.
        /// </summary>
        public override void undo()
        {
            m_Page.removeShape(m_TextShape.ID, getActionOrigin());
        }

        /// <summary>
        /// Redoes the action.
        /// </summary>
        public override void redo()
        {
            m_Page.addShape(m_TextShape, getActionOrigin());
        }

        /// <summary>
        /// Called when we receive a touch-down event.
        /// </summary>
        public override void onTouchDown(TouchArgs touchArgs)
        {
            // If we already have a text shape, this means that the user has been
            // editing this text and then clicked elsewhere on the screen. We take
            // this to mean that they have finished with this text and want to start
            // writing new text in the new location...
            if (textHasBeenEdited() == true)
            {
                m_TextShape.editCompleted(getActionOrigin());
                raiseActionCompletedEvent();
                return;
            }

            // We are not yet managing a valid piece of text, so we set the text
            // position to the clicked position so that we can start editing and
            // showng it in that location...
            PointF shapePosition = m_PageViewerControl.clientPointToShapePoint(touchArgs.ClientPosition);
            m_TextShape.setTopLeft(shapePosition, getActionOrigin());
        }

        /// <summary>
        /// Called when we receive a touch-move event. We do not do anything for the
        /// text shape.
        /// </summary>
        public override void onTouchMove(TouchArgs touchArgs)
        {
        }

        /// <summary>
        /// Called when we receive a touch-up event. We do not do anything for the
        /// text shape.
        /// </summary>
        public override void onTouchUp(TouchArgs touchArgs)
        {
        }

        #endregion

        #region Private functions

        /// <summary>
        /// Called when a key has been pressed.
        /// </summary>
        void onKeyPress(object sender, KeyPressEventArgs e)
        {
            // TODO: are there contsants for these key values?
            switch ((int)e.KeyChar)
            {
                case 13:
                    m_TextShape.addLine(getActionOrigin());
                    break;

                case 8:
                    m_TextShape.delete(getActionOrigin());
                    break;

                default:
                    m_TextShape.addChar(e.KeyChar, getActionOrigin());
                    break;
            }
        }

        /// <summary>
        /// Returns whether the text has been fully set up and
        /// contains data.
        /// </summary>
        private bool textHasBeenEdited()
        {
            // Does the shape contain any lines?
            IList<string> listLines = m_TextShape.getLines();
            if (listLines.Count == 0)
            {
                return false;
            }

            // Does the shape have just one empty line?
            if (listLines.Count == 1 && listLines[0] == "")
            {
                return false;
            }

            return true;
        }

        #endregion

        #region Private data

        // The shape we're managing...
        private Shape_Text m_TextShape = null;

        // TODO: this should not be here, as we have no good way of unregistering from its events. Maybe pass in keypress events??
        private KeyboardHook m_Keyboard = new KeyboardHook();

        #endregion
    }
}
